import socket
import datetime
import os
import re
import shutil
from threading import Thread


class SyslogServer:
    def __init__(self, host='0.0.0.0', port=1514, log_dir='logs'):
        self.host = host
        self.port = port
        self.log_dir = log_dir
        self.running = False
        self.sock = None
        self.current_date = None  # 记录当前日志文件对应的日期
        self.log_file = None  # 当前日志文件对象

        # 创建日志目录
        os.makedirs(log_dir, exist_ok=True)

    def _clear_log_dir(self):
        """清空日志目录中的所有文件"""
        if os.path.exists(self.log_dir):
            for filename in os.listdir(self.log_dir):
                file_path = os.path.join(self.log_dir, filename)
                try:
                    if os.path.isfile(file_path) or os.path.islink(file_path):
                        os.unlink(file_path)
                    elif os.path.isdir(file_path):
                        shutil.rmtree(file_path)
                except Exception as e:
                    print(f"[!] Failed to delete {file_path}: {e}")
    def start(self):
        # 新增：检测 log 文件夹是否存在日志文件并进行备份和清空
        if os.path.exists(self.log_dir):
            # 检查是否有日志文件
            log_files = [f for f in os.listdir(self.log_dir) if os.path.isfile(os.path.join(self.log_dir, f))]
            if log_files:
                old_log_dir = os.path.join(os.path.dirname(self.log_dir), 'old_log')
                os.makedirs(old_log_dir, exist_ok=True)

                # 将现有日志文件移动到 old_log 文件夹，并处理重名文件
                for filename in log_files:
                    src_file = os.path.join(self.log_dir, filename)
                    dst_file = os.path.join(old_log_dir, filename)

                    base, ext = os.path.splitext(dst_file)
                    counter = 1
                    while os.path.exists(dst_file):
                        dst_file = f"{base}-{counter}{ext}"
                        counter += 1

                    shutil.move(src_file, dst_file)

        # 清空日志目录
        self._clear_log_dir()

        """启动服务器"""
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind((self.host, self.port))
        print(f"[*] Syslog Server start!，listen {self.host}:{self.port}")

        self.running = True
        Thread(target=self._listen, daemon=True).start()

    def stop(self):
        """停止服务器"""
        self.running = False
        if self.sock:
            self.sock.close()
        if self.log_file:
            self.log_file.close()
        print("[*] server is stoped!")

    def _listen(self):
        """监听日志消息"""
        while self.running:
            try:
                data, addr = self.sock.recvfrom(1024)
                message = data.decode('utf-8', errors='replace').strip()
                self._process_message(message, addr)
            except OSError:
                break  # 正常停止时退出

    def _process_message(self, message, addr):
        """处理日志消息"""
        # 获取当前日期用于文件名
        level = 'Unknown'
        date_str = datetime.datetime.now().strftime("%Y-%m-%d")
        # timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        # 尝试解析日志等级
        pri_match = re.match(r'<(\d+)>', message)
        if pri_match:
            pri = int(pri_match.group(1))
            severity = pri & 0x07
            severity_levels = {
                0: 'Emergency',
                1: 'Alert',
                2: 'Critical',
                3: 'Error',
                4: 'Warning',
                5: 'Notice',
                6: 'Informational',
                7: 'Debug'
            }
            level = severity_levels.get(severity, 'Unknown')

        # 格式化输出
        output = f"[{addr[0]}] [{level}]{message}"
        # output = f"[{timestamp}] [{addr[0]}] [{level}]{message}"

        # 输出到控制台
        print(output)

        # 写入日志文件
        # log_file = os.path.join(self.log_dir, f"syslog-{date_str}.log")
        # with open(log_file, 'a', encoding='utf-8') as f:
        #     f.write(output + '\n')
        if self.current_date != date_str or self.log_file is None:
            if self.log_file:
                self.log_file.close()
            self.current_date = date_str
            log_file_path = os.path.join(self.log_dir, f"syslog-{date_str}.log")
            self.log_file = open(log_file_path, 'a', encoding='utf-8')

        try:
            self.log_file.write(output + '\n')
            self.log_file.flush()
            os.fsync(self.log_file.fileno())
        except Exception as e:
            print(f"[!] wirte log to file failed: {e}")


if __name__ == "__main__":
    server = SyslogServer()

    try:
        server.start()
        # 保持主线程运行
        while True:
            pass
    except KeyboardInterrupt:
        server.stop()